#ifndef _SSD1306_H_
#define _SSD1306_H_

#include "esp_err.h"
#include "driver/i2c_master.h"

#define SSD1306_WIDTH               128
#define SSD1306_HEIGHT              64
#define SSD1306_I2C_ADDR            0x3C    // 默认I2C地址，可能是0x3C或0x3D


// 命令定义
#define SSD1306_CMD_SETLOWCOLUMN    0x00
#define SSD1306_CMD_SETHIGHCOLUMN   0x10
#define SSD1306_CMD_MEMORYMODE      0x20
#define SSD1306_CMD_COLUMNADDR      0x21
#define SSD1306_CMD_PAGEADDR        0x22
#define SSD1306_CMD_SETCONTRAST     0x81
#define SSD1306_CMD_CHARGEPUMP      0x8D
#define SSD1306_CMD_DISPLAYALLON_RESUME 0xA4
#define SSD1306_CMD_NORMALDISPLAY   0xA6
#define SSD1306_CMD_INVERTDISPLAY   0xA7
#define SSD1306_CMD_SETMULTIPLEX    0xA8
#define SSD1306_CMD_DISPLAYOFF      0xAE
#define SSD1306_CMD_DISPLAYON       0xAF
#define SSD1306_CMD_SETPAGEADDR     0xB0
#define SSD1306_CMD_COMSCANDEC      0xC8   // 从左到右扫描
#define SSD1306_CMD_SEGREMAP_INV    0xA1 // 正常SEG重映射
#define SSD1306_CMD_COMSCANINC      0xC0   // 从右到左扫描
#define SSD1306_CMD_SEGREMAP        0xA0 // 反向SEG重映射


#define SSD1306_CMD_SETDISPLAYOFFSET 0xD3
#define SSD1306_CMD_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_CMD_SETPRECHARGE    0xD9
#define SSD1306_CMD_SETCOMPINS      0xDA
#define SSD1306_CMD_SETVCOMDETECT   0xDB

// 颜色定义
#define SSD1306_COLOR_BLACK         0
#define SSD1306_COLOR_WHITE         1

// 索引计算
#define ssd1306_index(x, y) (x + (y / 8) * SSD1306_WIDTH)
#define ssd1306_bitmask(y) (1 << (y % 8))


/**
 * @brief 初始化SSD1306 OLED显示屏
 *
 * @return esp_err_t 返回ESP_OK表示成功，其他值表示失败
 */
esp_err_t ssd1306_init(void);

/**
 * @brief 使用已有的I2C总线初始化SSD1306 OLED显示屏
 *
 * @param bus_handle 已有的I2C总线句柄
 * @return esp_err_t 返回ESP_OK表示成功，其他值表示失败
 */
esp_err_t ssd1306_init_with_bus(i2c_master_bus_handle_t bus_handle);

/**
 * @brief 在指定位置设置光标
 *
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 */
void ssd1306_set_cursor(uint8_t x, uint8_t y);

/**
 * @brief 反转OLED显示屏
 *
 * @param reverse 0表示正常显示，1表示反转显示
 */
void ssd1306_reverse(uint8_t reverse);

/**
 * @brief 写入字符串到OLED显示屏
 *
 * @param str 字符串内容
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 * @param size 字体大小
 * @param color 颜色（White/Black）
 */
void ssd1306_write_string(const char *str, uint8_t x, uint8_t y, uint8_t size, uint8_t color);

/**
 * @brief 绘制单个字符
 *
 * @param ch 字符
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 * @param size 字体大小
 */
void ssd1306_write_char(const char ch, uint8_t x, uint8_t y, uint8_t size);

/**
 * @brief 绘制中文字符
 *
 * @param index 字符索引
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 * @param size 字体大小
 */
void ssd1306_write_chinese(uint8_t index, uint8_t x, uint8_t y, uint8_t size);

/**
 * @brief 清屏
 */
void ssd1306_clear(void);

/**
 * @brief 刷新OLED显示屏
 */
esp_err_t ssd1306_update(void);

/**
 * @brief 向OLED显示屏写入命令
 *
 * @param command 命令值
 * @return esp_err_t 命令写入成功返回ESP_OK，否则返回错误码
 */
esp_err_t ssd1306_write_command(uint8_t command);

/**
 * @brief 向OLED显示屏写入数据
 *
 * @param data 数据值
 * @return esp_err_t 数据写入成功返回ESP_OK，否则返回错误码
 */
esp_err_t ssd1306_write_data(uint8_t data);

/**
 * @brief 设置单个像素点亮
 *
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 */
void ssd1306_set_pixel(uint8_t x, uint8_t y);

/**
 * @brief 设置单个像素点灭
 *
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 */
void ssd1306_clear_pixel(uint8_t x, uint8_t y);

/**
 * @brief 获取单个像素点状态（是否点亮）
 *
 * @param x X轴坐标（像素）
 * @param y Y轴坐标（页）
 */
uint8_t ssd1306_get_pixel(uint8_t x, uint8_t y);

/**
 * @brief 绘制水平线
 *
 * @param x1 起始X轴坐标（像素）
 * @param x2 结束X轴坐标（像素）
 * @param y Y轴坐标（页）
 */
void ssd1306_draw_hline(uint8_t x1, uint8_t x2, uint8_t y);

/**
 * @brief 绘制垂直线
 *
 * @param x X轴坐标（像素）
 * @param y1 起始Y轴坐标（页）
 * @param y2 结束Y轴坐标（页）
 */
void ssd1306_draw_vline(uint8_t x, uint8_t y1, uint8_t y2);

/**
 * @brief 绘制矩形
 * @param x1 起始X轴坐标（像素）
 * @param y1 起始Y轴坐标（页）
 * @param x2 结束X轴坐标（像素）
 * @param y2 结束Y轴坐标（页）
 */
void ssd1306_draw_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);

/**
 * @brief 填充矩形
 * @param x1 起始X轴坐标（像素）
 * @param y1 起始Y轴坐标（页）
 * @param x2 结束X轴坐标（像素）
 * @param y2 结束Y轴坐标（页）
 */
void ssd1306_fill_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);

#endif // _SSD1306_H_